package com.franklin.ideaplugin.api.utils.psi;

import com.franklin.ideaplugin.api.constants.PsiConstants;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.othelle.jtuples.Tuple1;
import com.othelle.jtuples.Tuple2;
import com.othelle.jtuples.Tuples;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * @author Ye Junhui
 * @since 2024/1/3
 */
public class PsiTypeUtils implements PsiConstants {

    /**
     * 获取真正的类型
     * @param psiType
     * @return
     */
    public static PsiType getActualPsiType(PsiType psiType){
        // ? extends xx 获取真正类型
        if (psiType instanceof PsiWildcardType){
            PsiWildcardType psiWildcardType = (PsiWildcardType) psiType;
            psiType = psiWildcardType.getBound();
        }
        return psiType;
    }

    /**
     * 异常
     * @param psiType
     */
    public static IllegalArgumentException getPsiTypeError(PsiType psiType){
        return new IllegalArgumentException("psiType " + psiType + "is not supported");
    }

    /**
     * 异常
     * @param psiType
     */
    public static void throwingPsiTypeError(PsiType psiType){
        throw getPsiTypeError(psiType);
    }

    /**
     * 是否是目标java类型
     * @param project
     * @param psiType
     * @param targetJavaClass
     * @return
     */
    public static boolean isTargetJavaType(Project project,PsiType psiType,Class<?> targetJavaClass){
        return isTargetJavaType(project,psiType,targetJavaClass.getName());
    }

    /**
     * 是否是目标java类型
     * @param project
     * @param psiType
     * @param classQualifiedName
     * @return
     */
    public static boolean isTargetJavaType(Project project,PsiType psiType,String classQualifiedName){
        if (!(psiType instanceof PsiClassType)) {
            return false;
        }
        PsiClassType psiClassType = (PsiClassType) psiType;
        PsiClass psiClass = psiClassType.resolve();
        PsiClass targetPsiClass = PsiClassUtils.findPsiClass(project, classQualifiedName);
        return PsiClassUtils.isInheritorOrEquals(targetPsiClass,psiClass);
    }

    /**
     * 解析类的泛型map
     * @param psiClassType
     * @return
     */
    public static Map<String,PsiType> resolveGenericTypeMap(PsiClassType psiClassType){
        if (psiClassType.getParameterCount() <= 0){
            return Maps.newLinkedHashMap();
        }
        PsiClass psiClass = psiClassType.resolve();
        if (Objects.isNull(psiClass)){
            return Maps.newLinkedHashMap();
        }

        PsiType[] genericParameters = psiClassType.getParameters();
        PsiTypeParameter[] typeParameters = psiClass.getTypeParameters();
        return IntStream.range(0,genericParameters.length)
                .mapToObj(i -> Tuples.tuple(typeParameters[i].getName(),genericParameters[i]))
                .collect(Collectors.toMap(
                        Tuple1::_1,
                        Tuple2::_2
                ));
    }
}
